﻿#pragma once
#include "CShareMem.h"
#include "CLock.h"

enum {
	MSG_CTRL_INFO = 0,
	MSG_CTRL_START,
	MSG_Alarm,
	MSG_SQ_Start,
	MSG_MkStand_CNT
};

struct CMsgInfo
{
	CMsgInfo()
	{
		memset(msg, 0, 512);
	}
	~CMsgInfo()
	{
	}

	int nSrcID;
	int nDestID;
	int nType;
	unsigned char msg[512];	
};

struct QueueNode
{
	CMsgInfo info;

	int prev;
	int next;
};

//偏移量
struct QueueHead
{
	int emptyHead;
	int emptyTail;
	int fullHead;
	int fullTail;	
};

#define MSG_QUEUE_NAME (L"__MSG_QUEUE_NAME__")
#define MSG_QUEUE_LOCK_NAME (L"__MSG_QUEUE_LOCK_NAME__")
//使用偏移量是迫不得已，因为每个进程映射同一块共享内存到本程序空间得到的地址可能不一样
class CMsgQueue
{
	enum {MSG_QUEUE_LENGTH = 1024};
	enum {NPOS = -1};
public:
	CMsgQueue(void)
	{			
		pHead = 0;
		pBase = 0;
		pLock = 0;
	}
	~CMsgQueue(void)
	{
		if(pLock)
			delete pLock;
	}

	bool Open(int nQueueLength = MSG_QUEUE_LENGTH)
	{
		unsigned char* lpBuf = shmInfo.Open(MSG_QUEUE_NAME, sizeof(QueueHead) + nQueueLength*sizeof(QueueNode));
		if(!lpBuf) return false;	

		pLock = new CLock(MSG_QUEUE_LOCK_NAME);
		if(!pLock) return false;

		//定位队列头结构
		pHead = (QueueHead*)lpBuf;
		//定位队列基址
		pBase = (QueueNode*)(lpBuf+sizeof(QueueHead));

		//锁定队列
		pLock->Lock();
		//判断是否为首次创建		
		//如果空队列、满队列头偏移量都为0，说明该共享内存是刚建立的，还为初始化
		if((pHead->emptyHead == 0) && (pHead->fullHead == 0))
		{			
			pHead->emptyHead = 0;
			pHead->emptyTail = nQueueLength-1;	//因为是从0开始计数
			pHead->fullHead = NPOS;	//头和尾永远是同时为NPOS，不可能一个NPOS一个不NPOS
			pHead->fullTail = NPOS;

			QueueNode* pNode = pBase;

			//初始化队列
			for(int ii=0;ii<nQueueLength-1;ii++) 
			{
				pNode->prev = ii-1;
				pNode->next = ii+1;
				pNode++;
			}
			pNode->prev = nQueueLength-2;
			pNode->next = NPOS;
		}
		pLock->Unlock();

		return true;
	}

	bool SendMsg(const CMsgInfo& inMsg)
	{
		pLock->Lock();

		if(pHead->emptyHead == NPOS)
		{
			pLock->Unlock();
			return false;
		}
		else
		{
			int pos = pHead->emptyHead;

			memcpy(&pBase[pos], &inMsg, sizeof(CMsgInfo));

			//将该节点移出空队列
			pHead->emptyHead = pBase[pos].next;
			if(pBase[pos].next == NPOS)
			{
				pHead->emptyTail = NPOS;
			}

			//将该节点插入满队列，默认插入尾端
			pBase[pos].next = NPOS;

			if(pHead->fullTail != NPOS)
			{
				pBase[pos].prev = pHead->fullTail;		
				pHead->fullTail = pos;
			}
			else
			{
				pBase[pos].prev = NPOS;
				pHead->fullHead = pos;
				pHead->fullTail = pos;
			}

			pLock->Unlock();
			return true;
		}
	}

	bool PickupMsg(int nDest, CMsgInfo& outMsg)
	{
		pLock->Lock();

		if(pHead->fullHead == NPOS) 
		{
			pLock->Unlock();
			return false;
		}
		else
		{
			int pos = pHead->fullHead;
			while(pBase[pos].info.nDestID != nDest)
			{
				pos = pBase[pos].next;
				if(pos == NPOS)
					break;
			}
			//退出时，要么已经找到，要么已经到了队列的尾端
			if(pos == NPOS)
			{
				pLock->Unlock();
				return false;
			}

			memcpy(&outMsg, &pBase[pos], sizeof(CMsgInfo));

			//将该节点移出满队列
			int prev = pBase[pos].prev;
			int next = pBase[pos].next;
			if(prev != NPOS)
			{
				pBase[prev].next = next;
			}
			else
			{
				pHead->fullHead = next;
			}

			if(next != NPOS)
			{
				pBase[next].prev = prev;
			}
			else
			{
				pHead->fullTail = prev;
			}

			//将该节点添加到空队列，默认添加到队尾
			pBase[pos].next = NPOS;
			if(pHead->emptyTail != NPOS)
			{
				pBase[pos].prev = pHead->emptyTail;		
				pHead->emptyTail = pos;
			}
			else
			{
				pBase[pos].prev = NPOS;
				pHead->emptyHead = pos;
				pHead->emptyTail = pos;
			}

			pLock->Unlock();
			return true;
		}
	}

private:
	CShareMem shmInfo;
	CLock* pLock;

	QueueHead* pHead;		//队列头 结构指针
	QueueNode* pBase;		//队列基址指针
};
